#ifndef TB_REFLECTION_OBJECT_HPP__
#define TB_REFLECTION_OBJECT_HPP__

#include <boost/smart_ptr/detail/yield_k.hpp>

#include "../base/mutex.hpp"
#include "../base/tostring.hpp"

#include "type_traits.hpp"
#include "reflection.hpp"
#include "register.hpp"

TB_NAMESPACE_BEGIN

class Variant;
class Object;

template class TB_REFLECTION_API weak_ptr<Object>;
template class TB_REFLECTION_API enable_shared_from_this<Object>;

class TB_REFLECTION_API Object : public enable_shared_from_this<Object> {
  DECLARE_reflection(Object, NoneType);
 public:     
  Object();
  Object(const Object& rhs);
  Object& operator=(const Object& rhs);
	virtual ~Object();
	TB_INLINE bool IsKindOf(uint32 typeId) { return reflection::IsKindOf(TypeId(), typeId); }
	TB_INLINE const TCHAR* TypeName() { return reflection::GetTypeName(TypeId()); }
	TB_INLINE const TCHAR* TypeDescription() { return reflection::GetTypeDescription(TypeId()); }
  TB_INLINE void LockShared() { mutex_.LockShared(); }
  TB_INLINE void UnlockShared() { mutex_.UnlockShared(); }
  TB_INLINE void LockExclusive() { mutex_.LockExclusive(); }
  TB_INLINE void UnlockExclusive() { mutex_.UnlockExclusive(); }
 protected:
   struct Data {} data_;
   mutable SpinRWMutex mutex_;
};

template <typename T> struct
is_user_object<T, typename enable_if<boost::mpl::or_<is_same<Object, T>, is_base_of<Object, T> >::value >::type>
  : true_type {};

template <typename T> struct 
GetVariantTypeIdHelper<T, typename enable_if<is_user_object<T>::value >::type> {
  typedef typename remove_crv<T>::type type;
  static uint32 TypeId(const void* p) {
    return p ? static_cast<const Object*>(p)->TypeId() : T::ClassTypeId();
  }
};

template <typename T> struct 
GetVariantTypeIdHelper<T, typename enable_if<
  boost::mpl::and_<boost::mpl::not_<is_buildin_type<T> >, 
    boost::mpl::and_<boost::mpl::not_<is_smart_ptr<T> >, 
      boost::mpl::and_<boost::mpl::not_<is_user_object<T> >, 
        boost::mpl::and_<boost::mpl::not_<is_same<T, NoneType> >, is_class<T> > > > >::value >::type> { 
  static uint32 TypeId(const void* p) { 
   (void)p; 
    static const uint32 typeId = 
			reflection::RegisterType(new reflection::DefaultAllocator<T>(), _T(""));
    return typeId; 
  } 
}; 

TB_NAMESPACE_END

#define TB_LOCK_READ_OBJECT() \
  TB_NAMESPACE::SpinRWMutex::ScopedReadLock __lock_##__LINE__(mutex_)

#define TB_LOCK_WRITE_OBJECT() \
  TB_NAMESPACE::SpinRWMutex::ScopedWriteLock __lock_##__LINE__(mutex_)

#define TB_IMPLEMENT_COPY_CONSTRUCTOR(CLS) 											 \
CLS::CLS(const CLS& rhs) 																					 \
  : impl_(new CLS##Impl), super(rhs), data_(rhs.data_) { 																 \
  TB_NAMESPACE::SpinRWMutex::ScopedReadLock __lock(rhs.mutex_);  \
  *impl_ = *rhs.impl_; 																						 \
}

#define TB_IMPLEMENT_ASSIGN_OPERATOR(CLS) 	\
CLS& CLS::operator=(const CLS& rhs) { 				\
  if (&rhs != this) { 												\
    super::operator=(rhs); 										\
WAITING_MUTEX_##CLS: 													\
    int k = 0; 																\
    rhs.mutex_.LockShared(); 									\
    if (!mutex_.TryLockExclusive()) { 				\
      rhs.mutex_.UnlockShared(); 							\
      ::boost::detail::yield(k++); 						\
			goto WAITING_MUTEX_##CLS; 							\
    } 																				\
    data_ = rhs.data_; 												\
    *impl_ = *rhs.impl_; 											\
    mutex_.UnlockExclusive(); 								\
    rhs.mutex_.UnlockShared(); 								\
  } 																					\
  return *this; 															\
}

#endif //TB_REFLECTION_OBJECT_HPP__
